﻿using System;
using System.Collections.Generic;
using System.Text;
using VideoLan;
using System.Windows.Forms;

namespace MulticastTV
{
    /// <summary>
    /// Remux/transcode class
    /// </summary>
    class Transcode
    {
        VideoLan.VideoLanClient vlc_trans ;
        VideoLan.VlcMediaPlayer player_trans ;
        RemuxForm rf;

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="parent">Main form</param>
        public Transcode(RemuxForm parent)
        {
            rf = parent;
        }

        /// <summary>
        /// Start transcoding
        /// </summary>
        /// <param name="input">Input file</param>
        /// <param name="output">Output file</param>
        /// <param name="mux">Mux</param>
        /// <param name="vcodec">Video codec</param>
        /// <param name="acodec">Audio codec</param>
        /// <param name="vbrate">Video bitrate</param>
        /// <param name="abrate">Audio bitrate</param>
        /// <param name="pluginpath">Aplication startup path</param>
        /// <param name="duplicate">Show stream in window</param>

        public void start(string input, string output, string mux, string vcodec, string acodec,
                          string vbrate, string abrate, string pluginpath, bool duplicate)
        {
            string[] trans_args;
            if (mux == "flv")
                mux = "ffmpeg{mux=flv}";
            
             //avi writter not working in current libvlc 
            else if (mux == "avi")
            {
                mux = "ffmpeg{mux=avi}";
            }

            if (vcodec == "orig")
                vcodec = "";
            if (acodec == "orig")
                acodec = "";

            string dp = "";
            if (duplicate)
                dp = "dst=display,";
            else
                dp = "";

            string samplerate = "samplerate=44100";
            if (acodec == "ac3" || acodec=="mp2a")
                samplerate = "samplerate=48000";

            string deinterlace="";
            //this should be passed with AddOption
            if (Properties.Settings.Default.TranscodeDeinterlace)
                deinterlace = "--video-filter=dinterlace";

            string transoption = "";
            trans_args = new string[] {
                                  //"--sout=#transcode{vcodec="+vcodec+",vb="+vbrate+",acodec="+acodec+",ab="+abrate+",scale=1,deinterlace,audio-sync,"+samplerate+"}:duplicate{dst=standard{access=file,mux="+mux+",dst="+output+"}"+dp+"}",
                                  //"--plugin-path=" + pluginpath + @"\plugins\",
                                  "--ignore-config",
                                  "--dummy-quiet",
                                  "--sout-transcode-high-priority",
                                  "--no-sout-display-audio",
                                  "--no-high-priority",
                                  deinterlace
                                  };
            
            // tanscode audio and video
            if (acodec.Length > 0 && vcodec.Length > 0)
            {
                transoption = ":sout=#transcode{vcodec=" + vcodec + ",vb=" + vbrate + ",acodec=" + acodec + ",ab=" + abrate + ",scale=1,deinterlace,audio-sync," + samplerate + "}:duplicate{dst=standard{access=file,mux=" + mux + ",dst=" + output + "}" + dp + "}";
            }

           // transcode only video
            else if (acodec.Length == 0 && vcodec.Length > 0)
            {
                transoption = ":sout=#transcode{vcodec=" + vcodec + ",vb=" + vbrate + ",scale=1,deinterlace," + samplerate + "}:duplicate{dst=standard{access=file,mux=" + mux + ",dst=" + output + "}" + dp + "}";
            }
            
            //transcode only audio
            else if (acodec.Length>0 && vcodec.Length==0)
            {
                transoption = ":sout=#transcode{acodec=" + acodec + ",ab=" + abrate + "," + samplerate + "}:duplicate{dst=standard{access=file,mux=" + mux + ",dst=" + output + "}" + dp + "}";
            }

            //just remux
            else
            {
                transoption = ":sout=#duplicate{dst=standard{access=file,mux=" + mux + ",dst=" + output + "}" + dp + "}";
            }

            vlc_trans = new VideoLan.VideoLanClient(pluginpath, trans_args);
            player_trans = vlc_trans.NewMediaPlayer(rf.pictureBox1.Handle);
            VideoLan.VlcMedia media = vlc_trans.NewMedia(System.Text.Encoding.UTF8.GetBytes(input));
            media.AddOption(System.Text.Encoding.UTF8.GetBytes(transoption));

            player_trans.Load(media);

            player_trans.PositionChanged+=new EventHandler<PositionChangedEventArgs>(player_trans_PositionChanged);
            player_trans.StateChanged+=new EventHandler<VideoLan.StateChangedEventArgs>(player_trans_StateChanged);
            //player_trans.TimeChanged+=new EventHandler<TimeChangedEventArgs>(player_trans_TimeChanged);
            media.Dispose();
           
            player_trans.Play();

            rf.checkBox7.Invoke(new delegateEnableDisableControlls(greyControlls));
            rf.button1.Invoke(new delegateEnableDisableControlls(greyControlls));
        }

        public void stop()
        {
            if (player_trans != null && player_trans.State == VideoLan.VlcState.Playing)
                 player_trans.Stop();
        }

        public void clean()
        { 
            if (player_trans != null)
            {
                player_trans.Dispose();
                player_trans = null;
            }
            if (vlc_trans != null)
            {
                vlc_trans.Dispose();
                vlc_trans = null;
            }
            GC.Collect();
        }

        public delegate void delegateUpdateProgressBar(int percent);
        public delegate void delegateEnableDisableControlls();

        public void updateProgressBar(int percent)
        {
            if (rf != null && rf.Handle !=null)
            rf.progressBar1.Value = percent;
       }

        public void greyControlls()
        {
            if (rf != null && rf.Handle != null)
            {
                rf.checkBox7.Enabled = false;
                rf.button1.Enabled = false;
            }
        }

        public void ungreyControlls()
        {
            if (rf != null && rf.Handle != null)
            {
                rf.button1.Enabled = true;
                rf.checkBox7.Enabled = true;
            }
        }

        // not working
        //private void player_trans_TimeChanged(object sender, TimeChangedEventArgs e)
        //{

        //    if (player_trans != null && player_trans.State == VlcState.Playing)
        //    {
        //        long length = player_trans.Length;
        //        long pos = player_trans.Time;
        //        int pc = 0;
        //        if (length != 0)
        //            pc = (int)(((float)pos / (float)length)*100);

        //         rf.progressBar1.Invoke(new delegateUpdateProgressBar(updateProgressBar), Math.Min(pc, 100));
        //    }
        //}

        private void player_trans_PositionChanged(object sender, PositionChangedEventArgs e)
        {
            float tmp = player_trans.Position*100;
            int pc = (int)tmp;
            if (pc < 0)
                pc = 0;
            rf.progressBar1.Invoke(new delegateUpdateProgressBar(updateProgressBar), Math.Min(pc, 100));
        }
        
        private void player_trans_StateChanged(object sender, StateChangedEventArgs e)
        {
            switch (e.NewState)
            {
                case VlcState.Ended:
                    if (rf != null)
                    {
                        rf.progressBar1.Invoke(new delegateUpdateProgressBar(updateProgressBar), 100);
                        rf.checkBox7.Invoke(new delegateEnableDisableControlls(ungreyControlls));
                        rf.button1.Invoke(new delegateEnableDisableControlls(ungreyControlls));
                    }
                   // clean();
                    break;
                 case VlcState.Error:
                    rf.checkBox7.Invoke(new delegateEnableDisableControlls(ungreyControlls));
                    rf.button1.Invoke(new delegateEnableDisableControlls(ungreyControlls));
                    //stop();
                    //clean();
                    //Handle playing error
                    break;
                case VlcState.Buffering:
                    //Notify system is buffering
                    break;
                case VlcState.Playing:
                    // update max
                    long length = player_trans.Length;
                    long pos = player_trans.Time;
                    int pc = 0;
                    if (length !=0)
                        pc = (int)(((float)pos / (float)length) * 100);
                    rf.progressBar1.Invoke(new delegateUpdateProgressBar(updateProgressBar), Math.Min(pc,100));
                    break;
            }
        }
    }
}
